<!--
 * @Author: WuFeng <763467339@qq.com>
 * @Date: 2024-11-05 09:27:21
 * @LastEditTime: 2024-11-08 19:37:41
 * @LastEditors: WuFeng <763467339@qq.com>
 * @Description: WebSocket 测试工具
 * @FilePath: \markdown-magic\src\pages\WebSocketTester\page\entry\index.vue
 * Copyright 版权声明
-->

<template>
  <div class="pageWrap">
    <div class="descArea">
      Websocket是一种用于H5浏览器的实时通讯协议，可以做到数据的实时推送，可适用于广泛的工作环境，例如客服系统、物联网数据传输系统，该测试工具可用于websocket开发初期的测试工作
    </div>
    <a-row :gutter="16">
      <a-col :xs="10" :sm="10" :md="10" :lg="10" :xl="8" :xxl="6">
        <a-card class="setArea" title="连接信息" :bordered="true">
          <div class="linkInfo">
            <a-space>
              <a-input v-model:value="data.options.url" placeholder="连接的地址" />
              <a-button type="primary" :disabled="isConnect === true" @click="handleConnect">连接</a-button>
              <a-button type="primary" danger :disabled="isConnect === false" @click="handleClose">断开</a-button>
            </a-space>
          </div>
          <p class="desc">
            1.连接格式为 ws://IP或域名:端口（示例ws://124.222.224.186:8800）
            <br>
            2.对于内网的测试环境，只需填入服务端的内网IP和端口
            <br>
            3.可连接我上面提供的服务端ws地址来测试您自己的客户端
          </p>
          <div class="sendCon">
            <a-textarea
              ref="sendConRef"
              v-model:value="data.options.message"
              placeholder="发送的内容"
              :auto-size="{ minRows: 4, maxRows: 8 }"
              @focus="handleFocusMessage"
              @blur="handleBlurMessage"
            />
          </div>
          <div class="btns">
            <a-button type="primary" block :disabled="isConnect === false || data.options.message === ''" @click="handleSendMsg">发送（ctrl+回车）</a-button>
          </div>
        </a-card>
      </a-col>
      <a-col :xs="14" :sm="14" :md="14" :lg="14" :xl="16" :xxl="18">
        <a-card class="messageArea" title="消息窗口" :bordered="true">
          <template #extra>
            <a-button type="primary" danger :disabled="false" size="small" @click="handleClearMsg">清除信息</a-button>
          </template>
          <div class="messageList">
            <div class="messageItem" v-for="(item, index) in data.msgList" :key="index" :class="{ server: item.person === '服务器' }">
              <div class="info">
                <span>
                  {{ item.person }}
                </span>
                <span>
                  {{ formatTime(item.time) }}
                </span>
              </div>
              <div class="msg" v-html="item.msg">
              </div>
            </div>
          </div>
        </a-card>
      </a-col>
    </a-row>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import dayjs from 'dayjs'
import WebSocketSDK from '@/plugins/WebSocketSDK.js'

import { getCurrentWindow } from '@tauri-apps/api/window'
import { register, unregisterAll, isRegistered } from '@tauri-apps/plugin-global-shortcut'

const sendConRef = ref(null)

const formatTime = (time) => {
  return dayjs().format('HH:mm:ss')
}

const isConnect = ref(false)
const ws = ref(null)

const data = reactive({
  options: {
    url: 'ws://124.222.224.186:8800',
    message: '',
    messageFocus: false
  },
  msgList: []
})

const handleFocusMessage = () => {
  data.options.messageFocus = true
}
const handleBlurMessage = () => {
  data.options.messageFocus = false
}

// 连接
const handleConnect = () => {
  data.msgList.push({
    person: '你',
    time: new Date().getTime(),
    msg: '等待服务器握手包...'
  })
  // 实例化websocket
  ws.value = new WebSocketSDK({
    ip: data.options.url,
    // true 断开不重连 、 false 断开重连
    isReconnect: true
  }, function () {
    // error 回调
    data.msgList.push({
      person: '服务器',
      time: new Date().getTime(),
      msg: '和服务器断开连接！'
    })
    ws.value = null
    isConnect.value = false
  }, function () {
    // close 回调
    data.msgList.push({
      person: '服务器',
      time: new Date().getTime(),
      msg: '和服务器断开连接！'
    })
    ws.value = null
    isConnect.value = false
  })

  ws.value.onopen = (e) => {
    ws.value.isHeartflag = true
    isConnect.value = true
    data.msgList.push({
      person: '你',
      time: new Date().getTime(),
      msg: '收到服务器握手包.'
    })
    data.msgList.push({
      person: '服务器',
      time: new Date().getTime(),
      msg: '连接已建立，正在等待数据...'
    })
  }

  ws.value.onmessage = (e) => {
    data.msgList.push({
      person: '服务器',
      time: e.timeStamp,
      msg: e?.data??''
    })
  }
}

// 发送（ctrl+回车）
const handleSendMsg = async () => {
  if (isConnect.value === true && data.options.message !== '') {
    ws.value.request(data.options.message, function (data) {})
  }
}

// 断开
const handleClose = () => {
  try {
    ws.value.onclose()
  } catch (error) {
  } finally {
    ws.value = null
    isConnect.value = false
  }
}

// 清除信息
const handleClearMsg = () => {
  data.msgList = []
}

// 注册快捷键 TODO: 监听快捷键方案二
const GlobalShortcutRegister = async () => {
  // 新建窗口
  if (await isRegistered('CommandOrControl+Enter') === false) {
    await register('CommandOrControl+Enter', (e) => {
      if (e.state == 'Pressed') {
        // 聚焦到输入框
        if (data.options.messageFocus === true) {
          // 发送（ctrl+回车）
          handleSendMsg()
        }
      }
    })
  }
}
// 注销快捷键
const GlobalShortcutUnregister = async () => {
  await unregisterAll()
}

const init = async () => {
  // 窗口聚焦/失焦事件监听
  try {
    await getCurrentWindow().setFocus()
    const unlistenFocus = await getCurrentWindow().onFocusChanged(({ payload: focused }) => {
      if (focused) {
        // 窗口聚焦时注册快捷键
        GlobalShortcutRegister()
      } else {
        // 窗口失焦时注销快捷键
        GlobalShortcutUnregister()
      }
    })
  } catch (error) {
    alert(error)
  }
}
init()
</script>

<style lang="scss" scoped>
.pageWrap {
  .linkInfo{
    .ant-space{
      display: flex;
      :deep(.ant-space-item:nth-child(1)){
        flex: 1;
      }
    }
  }
  .descArea{
    line-height: 1.6em;
    font-size: 14px;
    color: #666;
    margin-bottom: 12px;
  }
  :deep(.ant-card){
    .ant-card-head{
      padding: 0 12px;
      min-height: 40px;
      background-color: #f9f9f9;
    }
    .ant-card-body{
      padding: 12px;
    }
  }
  .setArea{
    .desc{
      font-size: 14px;
      color: #666;
      line-height: 1.6em;
      margin: 12px 0;
    }
    .btns{
      margin-top: 12px;
    }
  }
  .messageArea{
    .messageList{
      .messageItem{
        margin-bottom: 10px;
        .info{
          color: green;
          span{
            margin-right: 10px;
          }
        }
        .msg{
          line-height: 1.6em;
        }
      }
      .server{
        .info{
          color: blue;
        }
      }
    }
  }
}
</style>